#pragma once
#include <regex>
#include "util.hpp"

class HttpRequest
{
public:
    void ReSet()
    {
        _method.clear();
        _path.clear();
        _version = "HTTP/1.1";
        _body.clear();
        _headers.clear();
        _params.clear();
        _matches = std::smatch();
    }
  
    void SetHeader(const std::string& key, const std::string& val) { _headers[key] = val; }
    bool HasHeader(const std::string& key) const { return _headers.find(key) != _headers.end(); }
    const std::string GetHeader(const std::string& key) const
    {
        auto it = _headers.find(key);
        if(it == _headers.end())
            return "";
        return it->second;
    }

    void SetParam(const std::string& key, const std::string& val) { _params[key] = val; }
    bool HasParam(const std::string& key) { return _params.find(key) != _params.end(); }
    std::string GetParam(const std::string& key)
    {
        auto it = _params.find(key);
        if(it == _params.end())
            return "";
        return it->second;
    }

    size_t ContentLength() const
    {
        const std::string cont_leng = GetHeader("Content-Length");
        if(cont_leng == "")
            return 0;
        return std::stol(cont_leng); 
    }

    bool Close() const
    {   
        const std::string& conn = GetHeader("Connection");
        if(conn == "" || conn == "close") // Connection字段不存在或是为close(短连接)
            return true;
        // Connection字段为keep_alive(长连接)
        return false;
    }
     
public:
    std::string _method;    //请求方法
    std::string _path;      //资源路径
    std::string _version = "HTTP/1.1";  //协议版本
    std::string _body;      //请求正文
    std::unordered_map<std::string, std::string> _headers;  //头部字段
    std::unordered_map<std::string, std::string> _params;   //查询字符串
    std::smatch _matches;   //为资源路径转为正则形式
};

class HttpResponse
{
public:
    HttpResponse(int statu = 200)
    :_statu(statu)
    { }

    void Reset()
    {
        _statu = 200;
        _headers.clear();
        _body.clear();
        _redirect = false;
        _redirect_url.clear();
    }

    void SetHeader(const std::string& key, const std::string& val) { _headers[key] = val; }
    bool HasHeader(const std::string& key) const { return _headers.find(key) != _headers.end(); }
    const std::string GetHeader(const std::string& key) const
    {
        auto it = _headers.find(key);
        if(it == _headers.end())
            return "";
        return it->second;
    }

    void SetContent(const std::string& body, const std::string& type = "text/html")
    {
        _body = body;
        SetHeader("Content-Type", type);
    }

    void SetRedirect(const std::string& url, int statu = 302) 
    {
        _statu = statu;
        _redirect = true;
        _redirect_url = url; 
    }

    bool Close() const 
    {   
        const std::string& conn = GetHeader("Connection"); 
        if(conn == "" || conn == "close") // Connection字段不存在或是为close(短连接)
            return true;
        // Connection字段为keep_alive(长连接)
        return false;
    }
    
public:
    int _statu; //状态码
    std::unordered_map<std::string, std::string> _headers;  //头部字段
    std::string _body; //响应正文
    bool _redirect = false; //是否重定向
    std::string _redirect_url; //重定向链接
};

enum Stage
{
    RECV_HTTP_LINE,
    RECV_HTTP_HEAD,
    RECV_HTTP_BODY,
    RECV_HTTP_OVER,
    RECV_HTTP_ERROR
};

#define MAX_LINE 8192

class HttpContext
{ 
private:
    // 接受缓冲区中的http请求的请求行(http请求的首行，与请求报头以换行符分隔)
    bool RecvHttpLine(Buffer& buffer)
    {
        if(_recv_statu != RECV_HTTP_LINE)
        {
            _recv_statu = RECV_HTTP_ERROR;
            _resp_statu = 400; //Bad Request
            return false;
        }

        std::string line;
        if(buffer.GetLine(&line) == false) //缓冲区中不存在换行符
        {
            if(buffer.ReadAbleSize() > MAX_LINE) 
            {
                _recv_statu = RECV_HTTP_ERROR;
                _resp_statu = 414; //URI Too Long
            }
            return false;
        }

        if(line.size() > MAX_LINE)
        {
            _recv_statu = RECV_HTTP_ERROR;
            _resp_statu = 414; //URI Too Long
            return false; 
        }
        if(ParseHttpLine(line) == false)
            return false;
        _recv_statu = RECV_HTTP_HEAD;
        return true;
    }

    // 解析缓冲区中的http请求的请求行
    bool ParseHttpLine(const std::string& line)
    {
        std::smatch matches;
        std::regex e("(GET|HEAD|POST|PUT|DELETE) ([^?]*)(?:\\?(.*))? (HTTP/1\\.[01])(?:\n|\r\n)?", std::regex::icase);
        if(std::regex_match(line, matches, e) == false) 
        {
            _recv_statu = RECV_HTTP_ERROR;
            _resp_statu = 400; //Bad Request
            return false;
        }
        
        // 请求方法，大小写都正确，统一为大写进行处理
        std::string& method = _request._method = matches[1]; 
        std::transform(method.begin(), method.end(), method.begin(), ::toupper);

        // url
        _request._path = Util::UrlDecode(matches[2]);

        // 查询字符串，形式为 key=value，之间由'&'分隔
        std::string query_string = matches[3];
        std::vector<std::string> query_string_array;
        Util::Split(query_string, "&", query_string_array);
        for(std::string& str : query_string_array)
        {
            std::vector<std::string> key_value;
            Util::Split(str, "=", key_value);
            if(key_value.size() != 2)
            {
                _recv_statu = RECV_HTTP_ERROR;
                _resp_statu =400; //Bad Request
                return false;
            }
            _request.SetParam(Util::UrlDecode(key_value[0]), Util::UrlDecode(key_value[1]));
        }

        // 协议版本
        _request._version = matches[4];

        return true;
    }

    // 接收缓冲区中的http请求的请求报头(一个键值对占一行，与请求报文以空行分隔)
    bool RecvHttpHead(Buffer& buffer)
    {
        if(_recv_statu != RECV_HTTP_HEAD)
        {
            _recv_statu = RECV_HTTP_ERROR;
            _resp_statu = 400; //Bad Request
            return false;
        }
        
        std::string line;
        while(true) 
        {
            if(buffer.GetLine(&line) == false) //缓冲区中不存在换行符
            {
                if(buffer.ReadAbleSize() > MAX_LINE) 
                {
                    _recv_statu = RECV_HTTP_ERROR;
                    _resp_statu = 414; //URI Too Long
                }
                return false;
            }

            if(line.size() > MAX_LINE)
            {
                _recv_statu = RECV_HTTP_ERROR;
                _resp_statu = 414; //URI Too Long
                return false; 
            }

            if(line == "\n" || line == "\r\n")
                break;
            
            if(ParseHttpHead(line) == false)
                return false;
        }

        _recv_statu = RECV_HTTP_BODY;
        return true;
    }

    // 解析缓冲区中的http请求的请求报头中的一个键值对(以": "分隔)
    bool ParseHttpHead(std::string& line)
    {
        if(line.back() == '\n') line.pop_back();
        if(line.back() == '\r') line.pop_back();

        std::vector<std::string> key_value;
        Util::Split(line, ": ", key_value);
        if(key_value.size() != 2)
        {
            _recv_statu = RECV_HTTP_ERROR;
            _resp_statu = 400; //Bad Request
            return false;
        }
        _request.SetHeader(Util::UrlDecode(key_value[0]), Util::UrlDecode(key_value[1]));
        return true;
    }

    // 接收缓冲区中的http请求的请求正文
    bool RecvHttpBody(Buffer& buffer)
    {
        if(_recv_statu != RECV_HTTP_BODY)
        {
            _recv_statu = RECV_HTTP_ERROR;
            //_resp_statu = 400; //Bad Request
            return false;
        }

        // 请求正文较长时，一次IO可能无法获取到完整的正文
        size_t remain_length = _request.ContentLength() - _request._body.size(); //总长度减去已获取的长度为剩余长度
        if(remain_length == 0) //全部正文都已获取
        {
            _recv_statu = RECV_HTTP_OVER;
            return true;
        }

        std::string content;
        if(buffer.ReadAbleSize() >= remain_length)
        {
            buffer.Read(&content, remain_length);
            _request._body += content;
            _recv_statu = RECV_HTTP_OVER;
            return true;
        }
        else
        {
            
            buffer.Read(&content);
            _request._body += content;
            return true;
        }
    }

public:
    void Reset()
    {
        _resp_statu = 200;
        _recv_statu = RECV_HTTP_LINE;
        _request.ReSet();
        _response.Reset();
    }

    int GetRespStatu()  { return _resp_statu; }
    Stage GetRecvStatu()    { return _recv_statu; }
    HttpRequest& GetRequest()   { return _request; }
    HttpResponse& GetResponse() { return _response; }

    Stage RecvHttpRequest(Buffer* buffer)
    {
        switch(_recv_statu)
        {
            case RECV_HTTP_LINE: RecvHttpLine(*buffer); 
            case RECV_HTTP_HEAD: RecvHttpHead(*buffer);
            case RECV_HTTP_BODY: RecvHttpBody(*buffer);
        }
        return _recv_statu;
    }

private:
    int _resp_statu = 200; //响应状态码
    Stage _recv_statu = RECV_HTTP_LINE;
    HttpRequest _request;
    HttpResponse _response;
};